package com.springboot.config.error;

import com.springboot.jwt.error.JwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description: 全局异常
 * @ControllerAdvice： 增强型控制器，对于控制器的全局配置放在同一个位置，全局异常的注解，放在类上。
 * @ControllerAdvice 默认只会处理controller层抛出的异常，如果需要处理service层的异常，需要定义一个自定义的MyException来继承RuntimeException类，然后@ExceptionHandler（MyException）即可。
 * @ExceptionHandler：指明需要处理的异常类型以及子类。注解放在方法上面。
 * @ControllerAdvice异常拦截注解,在方法上面加入@ExceptionHandler(对应的异常类.class)注解,这种方法可以是多个的,Exception是全局的异常处理,
 * @author: zyj
 * @create: 2020-08-26 09:20
 **/
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    private String ERROR_CODE = "500";
    private String PARAM_ERROR_CODE = "501";
    private String METHOD_NOT_FIND = "502";

    private String ERROR_MESSAGE = "服务错误，请联系管理员！";
    private String ERROR_PARAM_MESSAGE = "请求数据格式错误，请检查是否正确！";
    private String METHOD_NOT_FIND_MESSAGE = "请求方法错误！";


    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public ResponseEntity<Map<String, Object>> errorResult(Exception ex) {
        log.error("全局服务异常：", ex);
        Map<String, Object> errorResult = new HashMap<>();
        errorResult.put("code", ERROR_CODE);
        errorResult.put("msg", ERROR_MESSAGE);
        errorResult.put("data", "");

        //参数格式错误
        if(ex instanceof HttpMessageNotReadableException){
            errorResult.put("msg", ERROR_PARAM_MESSAGE);
        }

        //请求方法错误
        if(ex instanceof HttpRequestMethodNotSupportedException){
            errorResult.put("code", METHOD_NOT_FIND);
            errorResult.put("msg", METHOD_NOT_FIND_MESSAGE);
        }

        //token方法错误
        if(ex instanceof JwtException){
            errorResult.put("code", ((JwtException) ex).getErrorCode());
            errorResult.put("msg", ((JwtException) ex).getErrorMsg());
        }

        return new ResponseEntity<>(errorResult, HttpStatus.OK);
    }



    /***
    * @Description: 参数校验（ps：必填项等）
    * @Param: [e]
    * @return: org.springframework.http.ResponseEntity
    * @Author: zyj
    * @Date: 2020/12/2
    */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public ResponseEntity<Map<String, Object>> exception(MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        List<ObjectError> allErrors = bindingResult.getAllErrors();
        Map<String, Object> errorResult = new HashMap<>();

        allErrors.forEach(objectError -> {
            FieldError fieldError = (FieldError)objectError;
            errorResult.put("code", PARAM_ERROR_CODE);
            errorResult.put("msg", fieldError.getDefaultMessage());
            errorResult.put("data", "");
        });

        return new ResponseEntity<>(errorResult, HttpStatus.OK);
    }

//    /***
//     * @Description: 参数校验（ps：必填项等）
//     * @Param: [e]
//     * @return: org.springframework.http.ResponseEntity
//     * @Author: zyj
//     * @Date: 2020/12/2
//     */
//    @ExceptionHandler(UnexpectedTypeException.class)
//    @ResponseBody
//    public ResponseEntity exception(UnexpectedTypeException e) {
//        Map<String, Object> errorResult = new HashMap<>();
//
//        errorResult.put("code", PARAM_ERROR_CODE);
//        errorResult.put("msg", ERROR_PARAM_MESSAGE);
//        errorResult.put("data", "");
//
//        return new ResponseEntity<>(errorResult, HttpStatus.OK);
//    }

}
